package ee.ut.cs.mc.madp.p2pdivider.networking;

import static ee.ut.cs.mc.madp.p2pdivider.BaseDividerActivity.HANDLER_TOAST;
import static ee.ut.cs.mc.madp.p2pdivider.BaseDividerActivity.OP_SEPARATOR;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Set;

import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import android.os.Handler;
import android.os.Message;
import android.util.Log;
import ee.ut.cs.mc.madp.p2pdivider.BaseDividerActivity;
import ee.ut.cs.mc.madp.p2pdivider.Command;

/**
 * @author Kaarel Jõgeva
 *
 */
public class DividerServer extends WebSocketServer {

    public static final String TAG = DividerClient.class.getCanonicalName();

    private String newHostIp = null;
    private String myIp = null;
    private boolean started = false;
    private final Handler handler;

    public DividerServer(Handler handler, int serverport) {
        super(new InetSocketAddress((InetAddress) null, serverport));
        this.handler = handler;
    }

    @Override
    public void start() {
        if (!started) {
            started = true;
            super.start();
        }
    }

    @Override
    public void onOpen(WebSocket conn, ClientHandshake handshake) {
        String stuff = "Opened serverside " + handshake.getResourceDescriptor() + " for " + conn.getRemoteSocketAddress().getAddress().getHostAddress();
        Log.i(TAG, stuff);
        Message.obtain(handler, HANDLER_TOAST, stuff).sendToTarget();
    }

    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
        String stuff = "Closed because " + reason + "(" + code + ")";
        Log.i(TAG, stuff);
        Message.obtain(handler, HANDLER_TOAST, stuff).sendToTarget();

    }

    @Override
    public void onMessage(WebSocket conn, String message) {
        String stuff = "Received message! " + message + " from " + conn.getRemoteSocketAddress().getAddress().getHostAddress();
        Log.i(TAG, stuff);
        Message.obtain(handler, HANDLER_TOAST, stuff).sendToTarget();

        int index = -1;

        if ((index = message.indexOf(OP_SEPARATOR)) > -1) {
            String op = message.substring(0, index);
            String data = message.substring(index + 1);
            handleMessage(conn, Command.valueOf(op), data);
        }

    }

    private void handleMessage(WebSocket conn, Command command, String data) {
        switch (command) {
        case IP:
            Boolean isHost = Boolean.valueOf(data);
            if (isHost) {
                newHostIp = conn.getRemoteSocketAddress().getAddress().getHostName();
            } else {
                myIp = conn.getLocalSocketAddress().getAddress().getHostName(); // Store out own IP in case we are the actual host
            }
            break;
        case IP_PROPAGATE:
            Set<WebSocket> con = connections();
            synchronized (con) {
                for (WebSocket socket : con) { // Notify all active connections that new host is divider host
                    String text = Command.IP.name() + OP_SEPARATOR + (newHostIp == null ? myIp : newHostIp);
                    socket.send(text);
                }
            }

            // Stop the server after sending everyone the new IP.
            try {
                Message.obtain(handler, BaseDividerActivity.HANDLER_STOP_GREETER).sendToTarget();
                stop();
            } catch (IOException e) {

            } catch (InterruptedException e) {

            }
            break;
        default:
            break;
        }
    }

    @Override
    public void onMessage(WebSocket conn, ByteBuffer message) {
        String stuff = "Received binary message! Capacity: " + message.capacity();
        Log.i(TAG, stuff);
        Message.obtain(handler, HANDLER_TOAST, stuff).sendToTarget();
    }

    @Override
    public void onError(WebSocket conn, Exception ex) {
        String stuff = "Error! " + ex.getMessage();
        Log.i(TAG, stuff);
        Message.obtain(handler, HANDLER_TOAST, stuff).sendToTarget();
    }

    public String getNewHostIp() {
        return newHostIp;
    }
}